#include <QtEndian>
#include "testexecution.h"
#include <QDebug>
#include <QFile>
#include <QTextStream>
#include <QDateTime>
#include <QEventLoop>

using namespace TestDataModel;

TestExecution::TestExecution(QObject *parent)
    : QObject(parent), m_sendCount(0) {
    connect(&m_sendTimer, &QTimer::timeout, this, &TestExecution::onSendTimerTimeout);
    connect(&m_executionTimer, &QTimer::timeout, this, &TestExecution::onExecutionTimeout);
    connect(&m_udp, &UdpCommunicator::dataReceived, this, &TestExecution::onDataReceived);
    connect(&m_trdp, &TrdpCommunicator::dataReceived, this, &TestExecution::onTrdpDataReceived);
}

void TestExecution::configureUdp(const QString& sendIp, int sendPort,
                                 const QString& receiveIp, int receivePort) {
    m_udp.start(sendIp, sendPort, receiveIp, receivePort);
}

void TestExecution::configureTrdp(const QString& ownIp, const QString& remoteIp,
                                  const std::map<UINT32, UINT32>& publishers,
                                  const std::vector<UINT32>& subscribers) {
    m_trdp.start(ownIp, remoteIp, publishers, subscribers);
}

void TestExecution::executeTestCase(const TestCase& testCase, int caseIndex, QString ownIP, QString dstIP)
{
    m_currentCaseIndex = caseIndex;  // 保存当前案例索引
    QString totalResult;
    bool allGroupsPass = true;
    m_testResultRecords.clear();  // 清空历史记录

    setCurrentTestCase(testCase);

    // 发射"开始测试"进度
    emit testProgress(m_currentCaseIndex, QString("开始测试案例: %1").arg(testCase.name));

    for (int groupIdx = 0; groupIdx < testCase.testGroups.size(); groupIdx++) {
        // 关键修改：将当前循环的组索引同步到成员变量，确保发送和接收处理当前组
        m_currentGroupIndex = groupIdx;

        const TestGroup& group = testCase.testGroups[groupIdx];
        totalResult += QString("=== 第%1组测试 ===\n").arg(groupIdx + 1);

        // 发射"开始第N组"进度
        emit testProgress(m_currentCaseIndex, QString("开始第%1组测试").arg(groupIdx + 1));

        // 为每个测试组单独初始化TRDP通信 - 修改部分
        if (m_protocol == CommunicationProtocol::TRDP) {
            // 先停止之前的通信
            m_trdp.stop();
        }

        // 准备发送数据（适配QString类型的type）
        QMap<quint16, QByteArray> udpDataMap = prepareUdpData(group.inputData);
        // 发送数据（100ms周期，持续5s）
        // 根据协议类型准备和发送数据
        if (m_protocol == CommunicationProtocol::UDP)
        {
            QMap<quint16, QByteArray> dataMap = prepareUdpData(group.inputData);
            if (ownIP.isEmpty()) ownIP = "192.168.7.144";
            if (dstIP.isEmpty()) dstIP = "192.168.7.126";
            configureUdp(ownIP, 0, dstIP, 0);
            sendUdpData(dataMap);
        } else
        {
            QMap<UINT32, QByteArray> dataMap = prepareTrdpData(group.inputData);
            if (ownIP.isEmpty()) ownIP = "192.168.7.144";
            if (dstIP.isEmpty()) dstIP = "239.255.0.0";
            std::map<UINT32, UINT32> publishers; // comId -> 发送间隔(us)
            std::vector<UINT32> subscribers;     // comId 列表

            QSet<UINT32> inputComIdSet;
            QSet<UINT32> expectedComIdSet;
            // 只处理当前组的COMID - 修改部分
            for (const TestDataItem& item : group.inputData)
            {
                // 将 portOrCommid 添加到集合中（自动去重）
                inputComIdSet.insert(static_cast<UINT32>(item.portOrCommid));
            }
            // 遍历每个组的预期数据（以防有在预期中定义但输入中没有的 comId）
            for (const TestDataItem& item : group.expectedData)
            {
                expectedComIdSet.insert(static_cast<UINT32>(item.portOrCommid));
            }
            const UINT32 DEFAULT_SEND_INTERVAL_US = 100000;
            for (UINT32 comId : inputComIdSet)
            {
                publishers[comId] = DEFAULT_SEND_INTERVAL_US;
            }
            for (UINT32 comId : expectedComIdSet)
            {
                subscribers.push_back(comId);
            }
            configureTrdp(ownIP, dstIP, publishers, subscribers);
            sendTrdpData(dataMap);
        }
        // 接收并解析数据
        QMap<QString, QString> receivedData = receiveAndParseData(group.expectedData);
        // 对比结果
        QString groupResult = compareResults(group.expectedData, receivedData);
        totalResult += groupResult + "\n\n";

        // 发射"第N组完成"进度
        emit testProgress(m_currentCaseIndex,
                          QString("第%1组测试完成: %2")
                              .arg(groupIdx + 1)
                              .arg(groupResult.contains("通过") ? "通过" : "不通过"));

        // 判断组是否通过
        bool groupPass = groupResult.contains("结论：通过");
        if (!groupPass) {
            allGroupsPass = false;
        }

        // 记录结果
        recordGroupTestResult(testCase.name, groupIdx + 1, group.inputData,
                              group.expectedData, receivedData, groupPass);
    }

    // 当整个测试案例执行完毕后，停止TRDP通信
    if (m_protocol == CommunicationProtocol::TRDP) {
        qDebug() << "测试案例" << testCase.name << "执行完毕，停止TRDP通信。";
        m_trdp.stop();
    }

    totalResult += QString("=== 测试总结 ===\n");
    totalResult += allGroupsPass ? "所有组测试通过" : "部分组测试不通过";

    // 发射最终结果
    emit testCaseFinished(m_currentCaseIndex, totalResult);
}

void TestExecution::stopExecution() {
    m_sendTimer.stop();
    m_executionTimer.stop();
    m_receivedData.clear();  // 清空接收缓存
    m_sendCount = 0;
}

void TestExecution::onSendTimerTimeout() {
    if (m_currentTestCase.testGroups.isEmpty() || m_currentGroupIndex >= m_currentTestCase.testGroups.size()) {
        qWarning() << "无有效测试组可执行！";
        return;
    }
    m_sendCount++;
    const TestGroup& currentGroup = m_currentTestCase.testGroups[m_currentGroupIndex];
    if (m_protocol == CommunicationProtocol::UDP)
    {
        auto data = prepareUdpData(currentGroup.inputData);
        for (auto it = data.begin(); it != data.end(); ++it)
        {
            m_udp.sendData(it.key(), it.value());
        }
    }
    else{
        auto data = prepareTrdpData(currentGroup.inputData);
        for (auto it = data.begin(); it != data.end(); ++it)
        {
            m_trdp.sendData(it.key(), it.value());
        }
    }

    emit testProgress(m_currentCaseIndex, QString("发送数据, 次数: %1").arg(m_sendCount));
}

void TestExecution::onDataReceived(const QByteArray& data, int port) {
    if (m_currentGroupIndex >= m_currentTestCase.testGroups.size()) {
        return;
    }
    const TestGroup& currentGroup = m_currentTestCase.testGroups[m_currentGroupIndex];
    parseReceivedData(data, port, currentGroup.expectedData, false); // 明确标记为UDP
}

void TestExecution::onExecutionTimeout() {
    stopExecution();
     emit testProgress(m_currentCaseIndex, "测试执行超时，已停止发送数据");
}

void TestExecution::onTrdpDataReceived(const QByteArray& data, UINT32 comId) {
    if (m_currentGroupIndex >= m_currentTestCase.testGroups.size()) {
        return;
    }
    const TestGroup& currentGroup = m_currentTestCase.testGroups[m_currentGroupIndex];
    parseReceivedData(data, comId, currentGroup.expectedData, true); // ComID即portOrCommid
}

// 准备TRDP数据
QMap<UINT32, QByteArray> TestExecution::prepareTrdpData(const QList<TestDataItem>& dataItems) {
    QMap<UINT32, QByteArray> comIdDataMap;

    // 按COMID分组数据项
    QMap<UINT32, QList<TestDataItem>> comIdItemsMap;
    for (const auto& item : dataItems) {
        comIdItemsMap[item.portOrCommid].append(item); // 使用portOrCommid
    }

    for (auto it = comIdItemsMap.begin(); it != comIdItemsMap.end(); ++it) {
        UINT32 comId = it.key();
        const auto& items = it.value();

        int maxOffset = 0;
        for (const auto& item : items) {
            int itemSize = 0;
            if (item.type == "U8") itemSize = 1;
            else if (item.type == "U16") itemSize = 2;
            else if (item.type == "U32") itemSize = 4;
            else if (item.type == "BOOL") itemSize = 1;
            else {
                qWarning() << "未知数据类型：" << item.type << "，默认按1字节处理";
                itemSize = 1;
            }
            maxOffset = qMax(maxOffset, item.byteOffset + itemSize);
        }

        QByteArray data(maxOffset, 0);

        // 填充数据
        for (const auto& item : items) {
            if (item.byteOffset >= data.size()) continue;

            if (item.type == "U8") {
                quint8 value = item.value.toUInt();
                data[item.byteOffset] = static_cast<char>(value);
            } else if (item.type == "U16") {
                quint16 value = item.value.toUInt();
                value = qToBigEndian(value);
                memcpy(data.data() + item.byteOffset, &value, 2);
            } else if (item.type == "U32") {
                quint32 value = item.value.toUInt();
                value = qToBigEndian(value);
                memcpy(data.data() + item.byteOffset, &value, 4);
            } else if (item.type == "BOOL") {
                quint8 byte = static_cast<quint8>(data[item.byteOffset]);
                bool isTrue = (item.value.compare("true", Qt::CaseInsensitive) == 0) || (item.value == "1");
                if (isTrue) byte |= (1 << item.bitOffset);
                else byte &= ~(1 << item.bitOffset);
                data[item.byteOffset] = static_cast<char>(byte);
            } else {
                qWarning() << "不支持的数据类型：" << item.type;
            }
        }

        comIdDataMap[comId] = data;
    }

    return comIdDataMap;
}


// 准备UDP数据（核心修复：type改为QString匹配）
QMap<quint16, QByteArray> TestExecution::prepareUdpData(const QList<TestDataItem>& dataItems) {
    QMap<quint16, QByteArray> portDataMap;

    QMap<quint16, QList<TestDataItem>> portItemsMap; // 仍用quint16存储UDP端口
    for (const auto& item : dataItems) {
        portItemsMap[static_cast<quint16>(item.portOrCommid)].append(item); // 使用portOrCommid
    }

    for (auto it = portItemsMap.begin(); it != portItemsMap.end(); ++it) {
        quint16 port = it.key();
        const auto& items = it.value();

        int maxOffset = 0;
        for (const auto& item : items) {
            int itemSize = 0;
            // 修复1：枚举判断 → QString字符串匹配（严格区分大小写，与datamodel中一致）
            if (item.type == "U8") {
                itemSize = 1;
            } else if (item.type == "U16") {
                itemSize = 2;
            } else if (item.type == "U32") {
                itemSize = 4;
            } else if (item.type == "BOOL") {
                itemSize = 1;
            } else {
                qWarning() << "未知数据类型：" << item.type << "，默认按1字节处理";
                itemSize = 1;
            }
            maxOffset = qMax(maxOffset, item.byteOffset + itemSize);
        }

        QByteArray data(maxOffset, 0);

        for (const auto& item : items) {
            if (item.byteOffset >= data.size()) continue;

            // 修复2：枚举判断 → QString字符串匹配
            if (item.type == "U8") {
                quint8 value = item.value.toUInt();
                data[item.byteOffset] = static_cast<char>(value);
            } else if (item.type == "U16") {
                quint16 value = item.value.toUInt();
                value = qToBigEndian(value);
                memcpy(data.data() + item.byteOffset, &value, 2);
            } else if (item.type == "U32") {
                quint32 value = item.value.toUInt();
                value = qToBigEndian(value);
                memcpy(data.data() + item.byteOffset, &value, 4);
            } else if (item.type == "BOOL") {
                quint8 byte = static_cast<quint8>(data[item.byteOffset]);
                bool isTrue = (item.value.compare("true", Qt::CaseInsensitive) == 0)
                              || (item.value == "1");
                if (isTrue) {
                    byte |= (1 << item.bitOffset);
                } else {
                    byte &= ~(1 << item.bitOffset);
                }
                data[item.byteOffset] = static_cast<char>(byte);
            } else {
                qWarning() << "不支持的数据类型：" << item.type;
            }
        }

        portDataMap[port] = data;
    }

    return portDataMap;
}

// 解析接收的数据（核心修复：type改为QString匹配）
void TestExecution::parseReceivedData(const QByteArray& data, quint32 portOrCommid,
                                      const QList<TestDataItem>& expectedItems, bool isTrdp) {
    for (const auto& item : expectedItems) {
        // 根据协议类型检查端口或COMID是否匹配
        if ((!isTrdp && item.portOrCommid != portOrCommid) ||
            (isTrdp && item.portOrCommid != portOrCommid)) {
            continue;
        }

        if (item.byteOffset >= data.size()) continue;

        QVariant value;

        if (item.type == "U8") {
            value = static_cast<quint8>(data[item.byteOffset]);
        } else if (item.type == "U16") {
            quint16 val;
            memcpy(&val, data.data() + item.byteOffset, 2);
            value = qFromBigEndian(val);
        } else if (item.type == "U32") {
            quint32 val;
            memcpy(&val, data.data() + item.byteOffset, 4);
            value = qFromBigEndian(val);
        } else if (item.type == "BOOL") {
            quint8 byte = static_cast<quint8>(data[item.byteOffset]);
            bool boolVal = (byte & (1 << item.bitOffset)) != 0;
            value = boolVal ? "true" : "false";
        } else {
            qWarning() << "无法解析的数据类型：" << item.type;
            value = "未知类型";
        }

        m_receivedData[item.name] = value;
    }
}

// 发送UDP数据
void TestExecution::sendUdpData(const QMap<quint16, QByteArray>& udpDataMap) {
    m_sendCount = 0;
    m_receivedData.clear();
    // 设置发送周期100ms，持续5s
    m_sendTimer.start(100);
    m_executionTimer.start(5000);  // 5秒后超时停止
}

// 发送TRDP数据
void TestExecution::sendTrdpData(const QMap<UINT32, QByteArray>& trdpDataMap) {
    m_sendCount = 0;
    m_receivedData.clear();
    m_sendTimer.start(100);
    m_executionTimer.start(5000);  // 5秒后超时停止
}

// 接收并解析数据
QMap<QString, QString> TestExecution::receiveAndParseData(const QList<TestDataItem>& expectedData) {
    // 等待接收完成（依赖定时器超时）
    QEventLoop loop;
    connect(&m_executionTimer, &QTimer::timeout, &loop, &QEventLoop::quit);
    loop.exec();

    // 转换QVariant为QString
    QMap<QString, QString> receivedStrMap;
    for (const auto& key : m_receivedData.keys()) {
        receivedStrMap[key] = m_receivedData[key].toString();
    }
    return receivedStrMap;
}

// 对比结果
QString TestExecution::compareResults(const QList<TestDataItem>& expectedData, const QMap<QString, QString>& actualData) {
    QString result;
    bool allPass = true;

    for (const auto& item : expectedData) {
        QString name = item.name;
        QVariant value=item.value;
        QString expected = value.toString();
        QString actual = actualData.contains(name) ? actualData[name] : "未收到";

        result += QString("%1: %2 (预期: %3)\n")
                      .arg(name)
                      .arg(actual)
                      .arg(expected);

        if (actual != expected) {
            allPass = false;
        }
    }

    result += QString("\n结论: ") + (allPass ? "通过" : "不通过");
    return result;
}

// 记录组测试结果
void TestExecution::recordGroupTestResult(
    const QString& caseName,
    int groupNum,
    const QList<TestDataItem>& inputList,
    const QList<TestDataItem>& expectedList,
    const QMap<QString, QString>& receivedData,
    bool isPass) {

    TestResultRecord record;
    record.caseName = caseName;
    record.groupName = QString::number(groupNum);

    QString inputStr;
    for (const auto& item : inputList) {
        inputStr += QString("%1:%2,").arg(item.name).arg(item.value);
    }
    if (!inputStr.isEmpty()) inputStr.chop(1);
    record.inputVars = inputStr;

    QString outputVarsStr, expectedStr, actualStr;
    for (const auto& item : expectedList) {
        outputVarsStr += item.name + ",";
        expectedStr += QString("%1:%2,").arg(item.name).arg(item.value);
        actualStr += QString("%1:%2,").arg(item.name).arg(receivedData.value(item.name, "未接收"));
    }
    if (!outputVarsStr.isEmpty()) outputVarsStr.chop(1);
    if (!expectedStr.isEmpty()) expectedStr.chop(1);
    if (!actualStr.isEmpty()) actualStr.chop(1);

    record.outputVars = outputVarsStr;
    record.expectedResults = expectedStr;
    record.actualResults = actualStr;
    record.isPass = isPass ? "通过" : "不通过";

    m_testResultRecords.append(record);
}

// 导出CSV
void TestExecution::exportTestResultsToCsv(const QString& filePath) {
    QFile file(filePath);
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) {
        qWarning() << "CSV文件打开失败：" << file.errorString();
        return;
    }

    QTextStream out(&file);
    out.setEncoding(QStringConverter::Utf8);

    out << "测试案例名称,组号,输入变量名称及值,输出变量名称,预期结果,实际结果,是否通过\n";

    for (const auto& record : m_testResultRecords) {
        out << record.caseName << ","
            << record.groupName << ","
            << "\"" << record.inputVars << "\","
            << "\"" << record.outputVars << "\","
            << "\"" << record.expectedResults << "\","
            << "\"" << record.actualResults << "\","
            << record.isPass << "\n";
    }

    file.close();
    qInfo() << "CSV导出成功：" << filePath;
}
